﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;

using Storm.TextEditor.Core;
using Storm.TextEditor.Drawing.GDI;
using Storm.TextEditor.Editor;
using Storm.TextEditor.Editor.Text;
using Storm.TextEditor.Parser.Objects;
using Storm.TextEditor.Parser.Objects.Collections;

namespace Storm.TextEditor.Drawing
{
	/// <summary>
	/// Represents a painter that paints a TextEditorBase.
	/// </summary>
	public class DefaultPainter
		: IPainter
    {
        #region Fields

        private int firstSpanRow = 0;
        private int lastSpanRow  = 0;

        private int lastRow     = 0;
        private int yOffset     = 0;
        private int resizeCount = 0;

        private bool spanFound          = false;
        private bool renderCaretRowOnly = false;

        private TextEditorBase textEditorControl = null;
        private RenderItems    renderItems       = new RenderItems();

        private Word bracketStart = null;
        private Word bracketEnd   = null;

		private Graphics currentGraphics = null;

		#region Events

		/// <summary>
		/// Occurs when the default margins (gutter margin and line number margin) are being rendered.
		/// </summary>
		public event RenderMarginEventHandler RenderDefaultMargins;

		#endregion

		#endregion

		#region Methods

		#region Public

		/// <summary>
        /// Handles the Resize event of the parent TextEditorBase, reinitializes the graphics of the DefaultPainter.
        /// </summary>
        public void Resize()
        {
            resizeCount++;
            this.InitGraphics();
        }

		/// <summary>
		/// Measures the given string and returns the size of it.
		/// </summary>
		/// <param name="measureString">String to measure.</param>
		/// <returns>The found size.</returns>
        public Size MeasureString(string measureString)
        {
            renderItems.StringBuffer.Font = renderItems.FontNormal;
            return renderItems.StringBuffer.MeasureTabbedString(measureString, textEditorControl.TabSpaces);
        }

        /// <summary>
        /// Initializes GDI32 backbuffers and brushes.
        /// </summary>
        public void InitGraphics()
        {
            if (renderItems.BackgroundBrush != null)
                renderItems.BackgroundBrush.Dispose();

            if (renderItems.GutterMarginBrush != null)
                renderItems.GutterMarginBrush.Dispose();

            if (renderItems.LineNumberMarginBrush != null)
                renderItems.LineNumberMarginBrush.Dispose();

            if (renderItems.HighlightLineBrush != null)
                renderItems.HighlightLineBrush.Dispose();

            if (renderItems.LineNumberMarginBorderBrush != null)
                renderItems.LineNumberMarginBorderBrush.Dispose();

            if (renderItems.GutterMarginBorderBrush != null)
                renderItems.GutterMarginBorderBrush.Dispose();

            if (renderItems.OutlineBrush != null)
                renderItems.OutlineBrush.Dispose();

            renderItems.BackgroundBrush				= new GDIBrush(textEditorControl.BackColor);
            renderItems.GutterMarginBrush			= new GDIBrush(textEditorControl.GutterMarginColor);
            renderItems.LineNumberMarginBrush		= new GDIBrush(textEditorControl.LineNumberBackColor);
            renderItems.HighlightLineBrush			= new GDIBrush(textEditorControl.HighlightedLineColor);
            renderItems.LineNumberMarginBorderBrush = new GDIBrush(textEditorControl.LineNumberBorderColor);
            renderItems.OutlineBrush				= new GDIBrush(textEditorControl.OutlineColor);
			renderItems.CollapsedBackgroundBrush    = new GDIBrush(textEditorControl.CollapsedBackgroundColor);
			renderItems.SymbolBrush                 = new GDIBrush(textEditorControl.ExpansionSymbolColor);
			renderItems.ExpansionBackgroundBrush    = new GDIBrush(textEditorControl.ExpansionBackgroundColor);

            if (renderItems.FontNormal != null)
                renderItems.FontNormal.Dispose();

            if (renderItems.FontBold != null)
                renderItems.FontBold.Dispose();

            if (renderItems.FontItalic != null)
                renderItems.FontItalic.Dispose();

            if (renderItems.FontBoldItalic != null)
                renderItems.FontBoldItalic.Dispose();

            if (renderItems.FontUnderline != null)
                renderItems.FontUnderline.Dispose();

            if (renderItems.FontBoldUnderline != null)
                renderItems.FontBoldUnderline.Dispose();

            if (renderItems.FontItalicUnderline != null)
                renderItems.FontItalicUnderline.Dispose();

            if (renderItems.FontBoldItalicUnderline != null)
                renderItems.FontBoldItalicUnderline.Dispose();

            string font		= textEditorControl.FontName;
            float  fontsize	= textEditorControl.FontSize;

            renderItems.FontNormal				= new GDIFont(font, fontsize, false, false, false, false);
            renderItems.FontBold				= new GDIFont(font, fontsize, true, false, false, false);
            renderItems.FontItalic				= new GDIFont(font, fontsize, false, true, false, false);
            renderItems.FontBoldItalic			= new GDIFont(font, fontsize, true, true, false, false);
            renderItems.FontUnderline			= new GDIFont(font, fontsize, false, false, true, false);
            renderItems.FontBoldUnderline		= new GDIFont(font, fontsize, true, false, true, false);
            renderItems.FontItalicUnderline		= new GDIFont(font, fontsize, false, true, true, false);
            renderItems.FontBoldItalicUnderline = new GDIFont(font, fontsize, true, true, true, false);

            this.InitIMEWindow();
            if (textEditorControl != null)
            {
                if (textEditorControl.IsHandleCreated == true)
                {
                    if (renderItems.StringBuffer != null)
                        renderItems.StringBuffer.Dispose();

                    if (renderItems.SelectionBuffer != null)
                        renderItems.SelectionBuffer.Dispose();

                    if (renderItems.BackBuffer != null)
                        renderItems.BackBuffer.Dispose();

                    renderItems.StringBuffer		= new GDISurface(1, 1, textEditorControl, true);
                    renderItems.StringBuffer.Font	= renderItems.FontNormal;

                    int rowHeight = renderItems.StringBuffer.MeasureTabbedString("ABC", 0).Height + textEditorControl.TextEditor.RowPadding;
                    renderItems.BackBuffer		= new GDISurface(textEditorControl.ClientWidth, rowHeight, textEditorControl, true);
                    renderItems.SelectionBuffer = new GDISurface(textEditorControl.ClientWidth, rowHeight, textEditorControl, true);

					renderItems.BackBuffer.Font			= renderItems.FontNormal;
                    renderItems.SelectionBuffer.Font	= renderItems.FontNormal;

                    textEditorControl.ViewPoint.RowHeight = rowHeight;
                    textEditorControl.ViewPoint.CharWidth = renderItems.BackBuffer.MeasureTabbedString(" ", 0).Width;
                }
            }
        }

		/// <summary>
		/// Measures the given row and returns its size.
		/// </summary>
		/// <param name="measureRow">Row to measure.</param>
		/// <param name="paddingCharCount">Number of padding characters to use when creating and measuring the padding.</param>
		/// <returns>The size of the given row.</returns>
		public Size MeasureRow(Row measureRow, int paddingCharCount)
        {
			return this.MeasureRow(measureRow, paddingCharCount, 0);
		}

		/// <summary>
		/// Renders the caret of the TextEditor.
		/// </summary>
		/// <param name="g">Graphics to use when rendering.</param>
		public void RenderCaret(Graphics g)
		{
			renderCaretRowOnly = true;

			this.RenderAll(g);

			renderCaretRowOnly = false;
		}

		/// <summary>
		/// Renders all content of the TextEditor.
		/// </summary>
        public void RenderAll()
        {
			textEditorControl.ViewPoint.RowHeight = 0;
			textEditorControl.ViewPoint.CharWidth = 0;
            textEditorControl.SetupViewPoint();

            Graphics graphics = textEditorControl.CreateGraphics();
			graphics.SmoothingMode = SmoothingMode.AntiAlias;

			currentGraphics = graphics;
            this.RenderAll(graphics);
        }

		/// <summary>
		/// Renders all content of the TextEditor.
		/// </summary>
		/// <param name="g">Graphics to use when rendering.</param>
        public void RenderAll(Graphics g)
        {
            textEditorControl.SetupViewPoint();
            textEditorControl.InitScrollbars();

            this.SetBrackets();
            this.SetSpanIndicators();

            int firstVisibleRow = textEditorControl.ViewPoint.FirstVisibleRow;

            int difference = firstVisibleRow - lastRow;
            lastRow = firstVisibleRow;

            if (textEditorControl.SmoothScroll == true)
            {
                if (difference == 1)
                {
                    for (int i = textEditorControl.ViewPoint.RowHeight; i > 0; i -= textEditorControl.SmoothScrollSpeed)
                    {
                        yOffset = i + textEditorControl.ViewPoint.YOffset;
                        this.RenderAllBase(g);

                        g.Flush();
                    }
                }
                else if (difference == -1)
                {
                    for (int i = -textEditorControl.ViewPoint.RowHeight; i < 0; i += textEditorControl.SmoothScrollSpeed)
                    {
                        yOffset = i + textEditorControl.ViewPoint.YOffset;
                        this.RenderAllBase(g);

                        g.Flush();
                    }
                }
            }

            yOffset = textEditorControl.ViewPoint.YOffset;
            this.RenderAllBase(g);
        }

		/// <summary>
		/// Renders the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row to render.</param>
        public void RenderRow(int rowIndex)
        {
			RenderRow(rowIndex, 10);
		}

		/// <summary>
		/// Returns the Point at the given TextPoint.
		/// </summary>
		/// <param name="textPoint">TextPoint to find Point on.</param>
		/// <returns>The Point at the given TextPoint.</returns>
		public Point GetPixelAtTextPoint(TextPoint textPoint)
		{
			return this.GetTextPointPixelPos(textPoint);
		}

		/// <summary>
		/// Returns the TextPoint at the given coordinates.
		/// </summary>
		/// <param name="x">X coordinate to find TextPoint on.</param>
		/// <param name="y">Y coordinate to find TextPoint on.</param>
		/// <returns>The TextPoint at the given coordinates.</returns>
        public TextPoint GetTextPointAtPixel(int x, int y)
        {
            int rowIndex = y / textEditorControl.ViewPoint.RowHeight + textEditorControl.ViewPoint.FirstVisibleRow;
            rowIndex = Math.Min(rowIndex, textEditorControl.Document.VisibleRows.Count);

			Row row = null;
            if (rowIndex == textEditorControl.Document.VisibleRows.Count)
            {
                rowIndex--;
                row = textEditorControl.Document.VisibleRows[rowIndex];
                if (row.IsCollapsed == true)
                    row = row.ExpansionEndRow;

                return new TextPoint(row.Text.Length, row.Index);
            }

            rowIndex = Math.Max(rowIndex, 0);
            if (textEditorControl.Document.VisibleRows.Count != 0)
            {
                row = textEditorControl.Document.VisibleRows[rowIndex];
                rowIndex = textEditorControl.Document.IndexOf(row);
            }
            else
                return new TextPoint(0, 0);

            if (rowIndex == -1)
                return new TextPoint(-1, -1);

            if (row.IsCollapsed == false)
                return this.GetTextPointFromRowColumn(rowIndex, x);

            if (x < row.ExpansionPixelEnd - textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth)
                return this.GetTextPointFromRowColumn(rowIndex, x);
            else if (x >= row.ExpansionEndRow.ExpansionPixelStart - textEditorControl.ViewPoint.FirstVisibleColumn * 
				textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin)
            {
                return GetTextPointFromRowColumn(row.ExpansionEndRow.Index, x - row.ExpansionEndRow.ExpansionPixelStart + this.MeasureRow
					(row.ExpansionEndRow, row.ExpansionEndRow.ExpansionStartChar, row.ExpansionEndRow.ExpansionPixelStart).Width);
            }
            else
                return new TextPoint(row.ExpansionEndChar, row.Index);
        }

		/// <summary>
		/// Returns the maximum character width.
		/// </summary>
		/// <returns>The maximum character width.</returns>
        public int GetMaxCharWidth()
        {
            string charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            int maximumWidth = 0;

            foreach (char character in charTable)
            {
                int characterWidth = this.MeasureString(character + "").Width;
                if (characterWidth > maximumWidth)
                    maximumWidth = characterWidth;
            }

            return maximumWidth;
        }

		/// <summary>
		/// Disposes the DefaultPainter and its children.
		/// </summary>
        public void Dispose()
        {
			renderItems.Dispose();
		}

        #endregion

		#region Private

		/// <summary>
		/// Renders a rectangle with the given width and height at the given coordinates.
		/// </summary>
		/// <param name="x">X coordinate to render the rectangle at.</param>
		/// <param name="y">Y coordinate to render the rectangle at.</param>
		/// <param name="width">Width of the rectangle.</param>
		/// <param name="height">Height of the rectangle</param>
		private void RenderRectangle(int x, int y, int width, int height)
		{
			renderItems.SelectionBuffer.RenderTo(renderItems.BackBuffer, x, y, width, height, x, y);
		}

		/// <summary>
		/// Sets the font of the given GDISurface to the given values.
		/// </summary>
		/// <param name="bold">Whether the font should be bold.</param>
		/// <param name="italic">Whether the font should be italic.</param>
		/// <param name="underline">Whether the font should be underlined.</param>
		/// <param name="backBuffer">GDISurface to set font of.</param>
		private void SetFont(bool bold, bool italic, bool underline, GDISurface backBuffer)
		{
			if (bold == true)
				if (italic == true)
					if (underline == true)
						backBuffer.Font = renderItems.FontBoldItalicUnderline;
					else
						backBuffer.Font = renderItems.FontBoldItalic;
				else if (underline == true)
					backBuffer.Font = renderItems.FontBoldUnderline;
				else
					backBuffer.Font = renderItems.FontBold;
			else if (italic == true)
				if (underline == true)
					backBuffer.Font = renderItems.FontItalicUnderline;
				else
					backBuffer.Font = renderItems.FontItalic;
			else if (underline == true)
				backBuffer.Font = renderItems.FontUnderline;
			else
				backBuffer.Font = renderItems.FontNormal;
		}

		/// <summary>
		/// Sets the font of the RenderItems' StringBuffer GDISurface to the given values.
		/// </summary>
		/// <param name="bold">Whether the font should be bold.</param>
		/// <param name="italic">Whether the font should be italic.</param>
		/// <param name="underline">Whether the font should be underlined.</param>
		private void SetStringFont(bool bold, bool italic, bool underline)
		{
			GDISurface backBuffer = renderItems.StringBuffer;
			if (bold == true)
				if (italic == true)
					if (underline == true)
						backBuffer.Font = renderItems.FontBoldItalicUnderline;
					else
						backBuffer.Font = renderItems.FontBoldItalic;
				else if (underline == true)
					backBuffer.Font = renderItems.FontBoldUnderline;
				else
					backBuffer.Font = renderItems.FontBold;
			else if (italic == true)
				if (underline == true)
					backBuffer.Font = renderItems.FontItalicUnderline;
				else
					backBuffer.Font = renderItems.FontItalic;
			else if (underline == true)
				backBuffer.Font = renderItems.FontUnderline;
			else
				backBuffer.Font = renderItems.FontNormal;
		}

		/// <summary>
		/// Updates the DefaultPainter's local bracket values to match the TextEditor's Caret's current word.
		/// </summary>
		private void SetBrackets()
		{
			Segment currentSegment = null;

			bracketEnd = null;
			bracketStart = null;

			Word currentWord = textEditorControl.Caret.CurrentWord;
			if (currentWord != null)
			{
				currentSegment = currentWord.Segment;
				if (currentSegment != null)
				{
					if (currentWord == currentSegment.StartWord || currentWord == currentSegment.EndWord)
					{
						bracketEnd = currentSegment.EndWord;
						bracketStart = currentSegment.StartWord;
					}

					if (currentWord == null || currentWord.Pattern == null)
						return;

					if (currentWord.Pattern.BracketType == BracketType.EndBracket)
					{
						if (currentWord.Segment.StartRow == null)
							currentWord.Segment.StartRow = currentWord.Segment.StartWord.Row;

						Word word = textEditorControl.Document.GetStartBracketWord(currentWord,
							currentWord.Pattern.MatchingBracket, currentWord.Segment);

						bracketEnd = currentWord;
						bracketStart = word;
					}
					else if (currentWord.Pattern.BracketType == BracketType.StartBracket)
					{
						Word word = textEditorControl.Document.GetEndBracketWord(currentWord,
							currentWord.Pattern.MatchingBracket, currentWord.Segment);

						bracketEnd = word;
						bracketStart = currentWord;
					}
				}
			}
		}

		/// <summary>
		/// Sets the positions of the span indicators.
		/// </summary>
		private void SetSpanIndicators()
		{
			spanFound = false;
			Segment currentSegment = textEditorControl.Caret.CurrentSegment();

			if (currentSegment == null || currentSegment.StartWord == null || currentSegment.StartWord.Row == null ||
				currentSegment.EndWord == null || currentSegment.EndWord.Row == null)
			{
				return;
			}

			firstSpanRow = currentSegment.StartWord.Row.Index;
			lastSpanRow = currentSegment.EndWord.Row.Index;

			spanFound = true;
		}

		/// <summary>
		/// Initializes the IME Window of the TextEditor.
		/// </summary>
		private void InitIMEWindow()
		{
			if (textEditorControl.IMEWindow != null)
				textEditorControl.IMEWindow.SetFont(textEditorControl.FontName, textEditorControl.FontSize);
		}

		/// <summary>
		/// Measures the given row and returns its size.
		/// </summary>
		/// <param name="measureRow">Row to measure.</param>
		/// <param name="paddingCharCount">Number of padding characters to use when creating and measuring the padding.</param>
		/// <param name="xOffset">X coordinate to start at.</param>
		/// <returns>The size of the given row.</returns>
		private Size MeasureRow(Row measureRow, int paddingCharCount, int xOffset)
		{
			int width = 0;

			int xPos = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
			int maximumTextWidth = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth +
				textEditorControl.ViewPoint.TextMargin;

			if (measureRow.InQueue == true)
			{
				this.SetStringFont(false, false, false);

				int padding = Math.Max(paddingCharCount - measureRow.Text.Length, 0);
				string paddingString = new string(' ', padding);

				string emptyText = measureRow.Text + paddingString;
				width = renderItems.StringBuffer.MeasureTabbedString(emptyText.Substring(0, paddingCharCount), textEditorControl.PixelTabSize).Width;
			}
			else
			{
				int charIndex = 0;
				int addedWidth = 0;
				int charPosition = 0;

				foreach (Word word in measureRow.FormattedWords)
				{
					if (word.Type == WordType.Word && word.Style != null)
						this.SetStringFont(word.Style.Bold, word.Style.Italic, word.Style.Underline);
					else
						this.SetStringFont(false, false, false);

					if (word.Text.Length + charIndex >= paddingCharCount || word == measureRow.FormattedWords[measureRow.FormattedWords.Count - 1])
					{
						charPosition = paddingCharCount - charIndex;

						int maximumCharacterPosition = Math.Min(charPosition, word.Text.Length);
						if (maximumCharacterPosition < 0)
							break;

						addedWidth += renderItems.StringBuffer.DrawTabbedString(word.Text.Substring(0, maximumCharacterPosition), xPos +
							addedWidth, 0, maximumTextWidth, textEditorControl.PixelTabSize).Width;

						width = addedWidth;
						break;
					}
					else
					{
						addedWidth += renderItems.StringBuffer.DrawTabbedString(word.Text, xPos + addedWidth, 0, maximumTextWidth,
							textEditorControl.PixelTabSize).Width;

						charIndex += word.Text.Length;
					}
				}

				this.SetStringFont(false, false, false);

				int padding = Math.Max(paddingCharCount - measureRow.Text.Length, 0);
				string paddingString = new string(' ', padding);

				width += renderItems.StringBuffer.DrawTabbedString(paddingString, xPos + addedWidth, 0, maximumTextWidth,
					textEditorControl.PixelTabSize).Width;
			}

			return new Size(width, 0);
		}

		/// <summary>
		/// Returns the TextPoint that is the closest to a character at the given y coordinate in the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="y">Y of the TextPoint to find.</param>
		/// <returns>The TextPoint that is the closest to a character at the given y coordinate in the row at the given index.</returns>
		private TextPoint GetTextPointFromRowColumn(int rowIndex, int y)
		{
			Row row = textEditorControl.Document[rowIndex];
			int maximumCharIndex = row.Text.Length;

			y -= textEditorControl.ViewPoint.TextMargin - 2 - textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

			if (row.Count == 0)
			{
				if (textEditorControl.VirtualWhitespace && textEditorControl.ViewPoint.CharWidth > 0)
					return new TextPoint(y / textEditorControl.ViewPoint.CharWidth, rowIndex);
				else
					return new TextPoint(0, rowIndex);
			}

			int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
			int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;

			int charIndex = 0;
			int totalWidth = 0;

			Word lastWord = null;
			Word currentWord = null;

			int wordWidth = 0;
			WordCollection wordCollection = row.FormattedWords;

			for (int i = 0; i < wordCollection.Count; i++)
			{
				currentWord = wordCollection[i];

				lastWord = currentWord;
				wordWidth = totalWidth;

				if (currentWord.Type == WordType.Word && currentWord.Style != null)
					this.SetStringFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline);
				else
					this.SetStringFont(false, false, false);

				int currentWordWidth = renderItems.StringBuffer.DrawTabbedString(currentWord.Text, x + totalWidth, 0, tabOrigin,
					textEditorControl.PixelTabSize).Width;

				if (totalWidth + currentWordWidth >= y)
					break;

				if (currentWord != row.FormattedWords[row.FormattedWords.Count - 1])
				{
					totalWidth += currentWordWidth;
					charIndex += currentWord.Text.Length;
				}
			}

			if (lastWord.Type == WordType.Word && lastWord.Style != null)
				this.SetStringFont(lastWord.Style.Bold, lastWord.Style.Italic, lastWord.Style.Underline);
			else
				this.SetStringFont(false, false, false);

			bool foundCharacter = false;
			foreach (char character in lastWord.Text)
			{
				int characterWidth = renderItems.StringBuffer.DrawTabbedString(character + "", x + wordWidth, 0, tabOrigin,
					textEditorControl.PixelTabSize).Width;

				if (wordWidth + characterWidth >= y)
				{
					foundCharacter = true;
					break;
				}

				charIndex++;
				wordWidth += characterWidth;
			}

			if (foundCharacter == false && textEditorControl.ViewPoint.CharWidth > 0 && textEditorControl.VirtualWhitespace == true)
			{
				int newY = y - wordWidth;
				int actualY = newY / textEditorControl.ViewPoint.CharWidth;

				charIndex += actualY;
			}

			if (charIndex < 0)
				charIndex = 0;

			return new TextPoint(charIndex, rowIndex);
		}

		/// <summary>
		/// Returns the caret's position as a Point.
		/// </summary>
		/// <returns>The caret's position as a Point.</returns>
		private Point GetCaretPixelPos()
		{
			return GetTextPointPixelPos(textEditorControl.Caret.Position);
		}

		/// <summary>
		/// Returns the Point at the given TextPoint.
		/// </summary>
		/// <param name="textPoint">TextPoint to find Point on.</param>
		/// <returns>The Point at the given TextPoint.</returns>
		private Point GetTextPointPixelPos(TextPoint textPoint)
		{
			Row row = textEditorControl.Document[textPoint.Y];

			if (row == null)
				return new Point();

			if (row.RowState == RowState.SegmentParsed)
				textEditorControl.Document.Parser.ParseLine(row.Index, true);

			Row expansionRow = null;

			if (row.IsCollapsedEndPart == true)
				expansionRow = row.ExpansionStartRow;
			else
				expansionRow = row;

			int expansionVisibleIndex = expansionRow.VisibleIndex;
			int y = (expansionVisibleIndex - textEditorControl.ViewPoint.FirstVisibleRow);

			if (y < 0 || y > textEditorControl.ViewPoint.VisibleRowCount)
				return new Point(-1, -1);

			y *= textEditorControl.ViewPoint.RowHeight;

			bool collapsed = row.IsCollapsedEndPart;
			int position = this.MeasureRow(row, textPoint.X, row.ExpansionPixelStart).Width + 1;

			if (collapsed == true)
			{
				position += row.ExpansionPixelStart;
				position -= MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
			}

			int x = position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
			if (x < textEditorControl.ViewPoint.TextMargin || x > textEditorControl.ViewPoint.ClientAreaWidth + textEditorControl.ViewPoint.TextMargin)
				return new Point(-1, -1);

			return new Point(x, y);
		}

		#endregion

        #region Protected

		/// <summary>
		/// Renders all content of the TextEditor.
		/// </summary>
		/// <param name="g">Graphics to use when rendering.</param>
        protected virtual void RenderAllBase(Graphics g)
        {
            int firstVisibleRow = textEditorControl.ViewPoint.FirstVisibleRow;
            Row row				= null;

            for (int i = 0; i < textEditorControl.ViewPoint.VisibleRowCount; i++)
            {
                if (firstVisibleRow >= 0 && firstVisibleRow < textEditorControl.Document.VisibleRows.Count)
                {
                    row = textEditorControl.Document.VisibleRows[firstVisibleRow];
                    if (renderCaretRowOnly == true)
                    {
                        if (row == textEditorControl.Caret.CurrentRow)
                            this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);

						if (textEditorControl.Caret.CurrentRow.ExpansionEndSegment != null &&
							textEditorControl.Caret.CurrentRow.ExpansionEndSegment.StartRow != null &&
							textEditorControl.Caret.CurrentRow.ExpansionEndSegment.StartRow == row)
						{
							this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);
						}
                    }
                    else
                        this.RenderRow(g, textEditorControl.Document.IndexOf(row), i);
                }
                else
                {
                    if (renderCaretRowOnly == false)
                        this.RenderRow(g, textEditorControl.Document.Count, i);
                }

                firstVisibleRow++;
            }
        }

		/// <summary>
		/// Renders the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="rowPosition">Position of the row.</param>
        protected virtual void RenderRow(int rowIndex, int rowPosition)
        {
            using (Graphics g = textEditorControl.CreateGraphics())
                this.RenderRow(g, rowIndex, rowPosition);
        }

		/// <summary>
		/// Renders the row at the given index.
		/// </summary>
		/// <param name="g">Graphics to use when rendering.</param>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="rowPosition">Position of the row.</param>
        protected virtual void RenderRow(Graphics g, int rowIndex, int rowPosition)
        {
            if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
            {
                if (textEditorControl.Document[rowIndex].RowState == RowState.SegmentParsed)
                {
                    textEditorControl.Document.Parser.ParseLine(rowIndex, true);
                    textEditorControl.Document[rowIndex].RowState = RowState.AllParsed;
                }
            }

            GDISurface backBuffer = renderItems.BackBuffer;
            bool       foundColor = false;

            GDIBrush backgroundBrush = renderItems.BackgroundBrush;
            if (rowIndex < textEditorControl.Document.Count && rowIndex >= 0)
            {
                Row row = textEditorControl.Document[rowIndex];
                if (spanFound && rowIndex >= firstSpanRow && rowIndex <= lastSpanRow && 
					textEditorControl.TextEditor.ScopeBackColor != Color.Transparent)
                {
                    backgroundBrush = new GDIBrush(textEditorControl.TextEditor.ScopeBackColor);
                    foundColor = true;
                }
                else if (row.BackColor != Color.Transparent)
                {
                    backgroundBrush = new GDIBrush(row.BackColor);
                    foundColor = true;
                }
                else
                {
                    if (row.EndSegment != null)
                    {
                        Segment endSegment = row.ExpansionEndSegment;
                        while (endSegment != null)
                        {
                            if (endSegment.Block.Transparent == false)
                            {
                                backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                foundColor = true;

                                break;
                            }

                            endSegment = endSegment.Parent;
                        }

                        if (foundColor == false)
                        {
                            endSegment = row.EndSegment;
                            while (endSegment != null)
                            {
                                if (endSegment.Block.Transparent == false)
                                {
                                    backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                    foundColor = true;

                                    break;
                                }

                                endSegment = endSegment.Parent;
                            }
                        }

                        if (foundColor == false)
                        {
                            endSegment = row.ExpansionEndSegment;
                            while (endSegment != null)
                            {
                                if (endSegment.Block.Transparent == false)
                                {
                                    backgroundBrush = new GDIBrush(endSegment.Block.BackColor);
                                    foundColor = true;

                                    break;
                                }

                                endSegment = endSegment.Parent;
                            }
                        }
                    }
                }
            }

            if (rowIndex == textEditorControl.Caret.Position.Y && textEditorControl.HighlightActiveLine == true)
                backBuffer.Clear(renderItems.HighlightLineBrush);
            else if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
            {
                if (textEditorControl.Document[rowIndex].IsCollapsed == true)
                {
					if (textEditorControl.Document[rowIndex].ExpansionEndRow.Index == textEditorControl.Caret.Position.Y &&
						textEditorControl.HighlightActiveLine == true)
					{
						backBuffer.Clear(renderItems.HighlightLineBrush);
					}
					else
						backBuffer.Clear(backgroundBrush);
                }
                else
                    backBuffer.Clear(backgroundBrush);
            }
            else
                backBuffer.Clear(backgroundBrush);

			if (rowIndex <= textEditorControl.Selection.LogicalBounds.FirstRow ||
				rowIndex >= textEditorControl.Selection.LogicalBounds.LastRow)
			{
				this.RenderText(rowIndex);
			}

            if (textEditorControl.Selection.IsValid == true)
            {
                if (rowIndex >= textEditorControl.Selection.LogicalBounds.FirstRow && 
					rowIndex <= textEditorControl.Selection.LogicalBounds.LastRow)
                {
                    if (textEditorControl.ContainsFocus == true)
                        renderItems.SelectionBuffer.Clear(textEditorControl.SelectionBackColor);
                    else
                        renderItems.SelectionBuffer.Clear(textEditorControl.InactiveSelectionBackColor);

                    this.RenderSelectedText(rowIndex);
                }
            }

            if (textEditorControl.ContainsFocus || textEditorControl.ViewPoint.Action == TextAction.DragText)
                this.RenderCaret(rowIndex, rowPosition * textEditorControl.ViewPoint.RowHeight + yOffset);

            this.RenderSelection(rowIndex);
            this.RenderMargins(rowIndex);

            if (textEditorControl.Document.Folding == true)
                this.RenderExpansion(rowIndex);

            RowPaintEventArgs e = new RowPaintEventArgs();
            Rectangle rectangle = new Rectangle(0, 0, textEditorControl.Width, textEditorControl.ViewPoint.RowHeight);

            e.Graphics = Graphics.FromHdc(backBuffer.HDC);
            e.Bounds   = rectangle;
            e.Row	   = null;

            if (rowIndex >= 0 && rowIndex < textEditorControl.Document.Count)
                e.Row = textEditorControl.Document[rowIndex];

            textEditorControl.TextEditor.OnRenderRow(e);
            e.Graphics.Dispose();

            backBuffer.Flush();
            backBuffer.RenderToControl(0, rowPosition * textEditorControl.ViewPoint.RowHeight + yOffset);

            if (foundColor == true)
                backgroundBrush.Dispose();
        }

		/// <summary>
		/// Renders collapsed, selected text of a row.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="x">X position to start at.</param>
        protected virtual void RenderCollapsedSelectedText(int rowIndex, int x)
        {
            GDISurface backBuffer = renderItems.SelectionBuffer;

            backBuffer.Font            = renderItems.FontBold;
            backBuffer.FontTransparent = true;

            Row row = textEditorControl.Document[rowIndex];
			string collapsedText = row.CollapsedText;

            x++;

            int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
            int textWidth = renderItems.StringBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
			renderItems.StringBuffer.Font = renderItems.FontNormal;
			renderItems.StringBuffer.FontTransparent = true;

            if (textEditorControl.ContainsFocus == true)
            {
                backBuffer.FillRect(textEditorControl.SelectionBackColor, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
				backBuffer.DrawRect(textEditorControl.SelectionBorderColor, x, 0, textWidth, textEditorControl.ViewPoint.RowHeight);
			}
            else
            {
                backBuffer.FillRect(textEditorControl.InactiveSelectionBackColor, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
				backBuffer.DrawRect(textEditorControl.SelectionBorderColor, x, 0, textWidth, textEditorControl.ViewPoint.RowHeight);
            }

            textWidth = backBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

            if (row.ExpansionStartSegment.EndRow != null)
            {
				if (row.ExpansionStartSegment.EndRow.RowState == RowState.SegmentParsed)
                    textEditorControl.Document.Parser.ParseLine(row.ExpansionStartSegment.EndRow.Index, true);

				Word endWord = row.ExpansionStartSegment.EndWord;
                x += textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

				row.ExpansionStartSegment.EndRow.ExpansionPixelStart = x + textWidth - textEditorControl.ViewPoint.TextMargin + 2;
                row.ExpansionPixelEnd = x - 1;

				this.RenderSelectedText(textEditorControl.Document.IndexOf(row.ExpansionStartSegment.EndRow), 
					row.ExpansionStartSegment.EndRow.ExpansionPixelStart, endWord);
            }
        }

		/// <summary>
		/// Renders collapsed text of a row.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="x">X position to start at.</param>
        protected virtual void RenderCollapsedText(int rowIndex, int x)
        {
            GDISurface backBuffer = renderItems.BackBuffer;

            backBuffer.Font            = renderItems.FontNormal;
            backBuffer.FontTransparent = true;
            backBuffer.TextForeColor   = textEditorControl.OutlineColor;

            Row row = textEditorControl.Document[rowIndex];
			string collapsedText = row.CollapsedText;

            x++;

            int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;
            int textWidth = renderItems.StringBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
			renderItems.StringBuffer.Font = renderItems.FontBold;

            backBuffer.FillRect(renderItems.OutlineBrush, x + 0, 0, textWidth + 2, textEditorControl.ViewPoint.RowHeight);
            backBuffer.FillRect(renderItems.BackgroundBrush, x + 1, 1, textWidth, textEditorControl.ViewPoint.RowHeight - 2);
            textWidth = backBuffer.DrawTabbedString(collapsedText, x + 1, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

			if (row.ExpansionStartSegment.EndRow != null)
            {
				if (row.ExpansionStartSegment.EndRow.RowState == RowState.SegmentParsed)
                    textEditorControl.Document.Parser.ParseLine(row.ExpansionStartSegment.EndRow.Index, true);

				Word endWord = row.ExpansionStartSegment.EndWord;
                x += textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth;

				row.ExpansionStartSegment.EndRow.ExpansionPixelStart = x + textWidth - textEditorControl.ViewPoint.TextMargin + 2;
                row.ExpansionPixelEnd = x - 1;

				this.RenderText(textEditorControl.Document.IndexOf(row.ExpansionStartSegment.EndRow),
					row.ExpansionStartSegment.EndRow.ExpansionPixelStart, endWord);
            }
        }

		/// <summary>
		/// Renders the text of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderText(int rowIndex)
        {
			this.RenderText(rowIndex, 0, null);
		}

		/// <summary>
		/// Renders the text of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="xOffset">X coordinate offset to start at.</param>
		/// <param name="startWord">Starting word.</param>
        protected virtual void RenderText(int rowIndex, int xOffset, Word startWord)
        {
            GDISurface backBuffer = renderItems.BackBuffer;

            backBuffer.Font            = renderItems.FontNormal;
            backBuffer.FontTransparent = true;

            bool drawBreakpoint = false;
            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                backBuffer.TextForeColor = Color.Black;
                Row row = textEditorControl.Document[rowIndex];

                int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset;

                int textWidth = 0;
                int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + 
					textEditorControl.ViewPoint.TextMargin;

                bool showWhitespace = textEditorControl.ShowWhitespace;
				bool startDraw      = startWord == null;

                row.ExpansionStartChar = 0;
                row.ExpansionEndChar = 0;
                bool expansion = false;

                WordCollection wordCollection = row.FormattedWords;
                Word           currentWord    = null;

                for (int i = 0; i < wordCollection.Count; i++)
                {
                    currentWord = wordCollection[i];

                    if (startDraw == true)
                    {
                        if (currentWord.Segment == row.ExpansionStartSegment && row.ExpansionStartSegment != null)
                        {
                            if (row.ExpansionStartSegment.Expanded == false)
                            {
                                this.RenderCollapsedText(rowIndex, x);
                                expansion = true;
                                break;
                            }
                        }

                        if ((currentWord.Type == WordType.Space || currentWord.Type == WordType.Tab) && drawBreakpoint == false && 
							textEditorControl.ShowTabGuides == true)
                        {
                            int xTabSize = x - (textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset);

                            if ((double)xTabSize / (double)textEditorControl.PixelTabSize == xTabSize / textEditorControl.PixelTabSize)
                                backBuffer.FillRect(textEditorControl.TabGuideColor, x, 0, 1, textEditorControl.ViewPoint.RowHeight);
                        }

                        if (currentWord.Type == WordType.Word || showWhitespace == false)
                        {
                            if (currentWord.Style != null)
                            {
                                this.SetFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline, backBuffer);

                                backBuffer.TextBackColor   = currentWord.Style.BackColor;
                                backBuffer.TextForeColor   = currentWord.Style.ForeColor;
                                backBuffer.FontTransparent = currentWord.Style.Transparent;
                            }
                            else
                            {
                                backBuffer.Font = renderItems.FontNormal;
                                backBuffer.TextForeColor = Color.Black;
                                backBuffer.FontTransparent = true;
                            }

                            if (currentWord.Type == WordType.Word)
                                drawBreakpoint = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

							if (currentWord.Segment != null && currentWord.Segment.Scope != null && currentWord.Segment.Scope.NoHighlighting == false)
							{
								if (textEditorControl.BracketMatching == true && (currentWord == bracketEnd || currentWord == bracketStart))
								{
									backBuffer.TextForeColor = textEditorControl.BracketForeColor;
									backBuffer.Font = new GDIFont(textEditorControl.FontName, textEditorControl.FontSize,
										textEditorControl.BracketBold, textEditorControl.BracketItalic,
										textEditorControl.BracketUnderline, textEditorControl.BracketStrikethrough);

									if (textEditorControl.BracketBackColor != Color.Transparent)
									{
										backBuffer.TextBackColor = textEditorControl.BracketBackColor;
										backBuffer.FontTransparent = false;
									}

									textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

									if (textEditorControl.BracketBorderColor != Color.Transparent)
									{
										backBuffer.DrawRect(textEditorControl.BracketBorderColor, x, 0, textWidth,
											textEditorControl.ViewPoint.RowHeight - 1);
									}
								}
								else
									textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
							}
							else
								textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                            if (currentWord.HasError == true || currentWord.HasWarning == true)
                            {
                                int lineY = textEditorControl.ViewPoint.RowHeight - 1;

                                Color color;
                                if (currentWord.HasError == true)
                                    color = currentWord.ErrorColor;
                                else
                                    color = currentWord.WarningColor;

                                for (int lineX = 0; lineX < textWidth + 3; lineX += 4)
                                {
                                    backBuffer.DrawLine(color, new Point(lineX + lineX, lineY), new Point(lineX + lineX + 2, lineY - 2));
                                    backBuffer.DrawLine(color, new Point(lineX + lineX + 2, lineY - 2), new Point(lineX + lineX + 4, lineY));
                                }
                            }
                        }
                        else if (currentWord.Type == WordType.Space && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.TextForeColor = textEditorControl.WhitespaceColor;
                            backBuffer.FontTransparent = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor   = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor   = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

                            backBuffer.DrawTabbedString("·", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }
                        else if (currentWord.Type == WordType.Tab && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.TextForeColor = textEditorControl.WhitespaceColor;
                            backBuffer.FontTransparent = true;

                            if (row.Breakpoint == true && drawBreakpoint == true)
                            {
                                backBuffer.TextForeColor   = textEditorControl.BreakpointForeColor;
                                backBuffer.TextBackColor   = textEditorControl.BreakpointBackColor;
                                backBuffer.FontTransparent = false;
                            }

                            backBuffer.DrawTabbedString("»", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }

						if (currentWord.Pattern != null)
						{
							if (currentWord.Pattern.IsSeparator == true)
							{
								backBuffer.FillRect(textEditorControl.SeparatorColor, textEditorControl.ViewPoint.TextMargin - 4, 
									textEditorControl.ViewPoint.RowHeight - 1, textEditorControl.ViewPoint.ClientAreaWidth, 1);
							}
						}

                        x += textWidth;
                    }

                    if (startDraw == false)
                        row.ExpansionStartChar += currentWord.Text.Length;

                    if (currentWord == startWord)
                        startDraw = true;

                    row.ExpansionEndChar += currentWord.Text.Length;
                }

                if (textEditorControl.TextEditor.ShowEOLMarker == true && expansion == false)
                {
                    backBuffer.Font = renderItems.FontNormal;
                    backBuffer.TextForeColor = textEditorControl.TextEditor.EOLMarkerColor;
                    backBuffer.FontTransparent = true;
                    backBuffer.DrawTabbedString("¶", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                }
            }
        }

		/// <summary>
		/// Renders the selected text of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderSelectedText(int rowIndex)
        {
			this.RenderSelectedText(rowIndex, 0, null);
		}

		/// <summary>
		/// Renders the selected text of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="xOffset">X coordinate offset to start at.</param>
		/// <param name="startWord">Starting word.</param>
        protected virtual void RenderSelectedText(int rowIndex, int xOffset, Word startWord)
        {
			GDISurface backBuffer = renderItems.SelectionBuffer;

            backBuffer.Font            = renderItems.FontNormal;
            backBuffer.FontTransparent = true;

            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                Row row = textEditorControl.Document[rowIndex];
                int x = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart + xOffset;

                int textWidth = 0;
                int tabOrigin = -textEditorControl.ViewPoint.FirstVisibleColumn * textEditorControl.ViewPoint.CharWidth + textEditorControl.ViewPoint.TextMargin;

                bool showWhitespace = textEditorControl.ShowWhitespace;
				bool startDraw      = startWord == null;	// Fancy little trick.

                row.ExpansionStartChar = 0;
                row.ExpansionEndChar   = 0;
                bool expansion = false;

                WordCollection wordCollection = row.FormattedWords;
                Word           currentWord    = null;

                for (int i = 0; i < wordCollection.Count; i++)
                {
                    currentWord = wordCollection[i];

                    if (startDraw == true)
                    {
						if (currentWord.Segment == row.ExpansionStartSegment && row.ExpansionStartSegment != null)
                        {
							if (row.ExpansionStartSegment.Expanded == false)
                            {
                                this.RenderCollapsedSelectedText(rowIndex, x);
                                expansion = true;
                                break;
                            }
                        }

                        if (currentWord.Type == WordType.Word || showWhitespace == false)
                        {
                            if (currentWord.Style != null)
                                this.SetFont(currentWord.Style.Bold, currentWord.Style.Italic, currentWord.Style.Underline, backBuffer);
                            else
                                backBuffer.Font = renderItems.FontNormal;

                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                            if (currentWord.HasError == true || currentWord.HasWarning == true)
                            {
                                int lineY = textEditorControl.ViewPoint.RowHeight - 1;

                                Color color;
                                if (currentWord.HasError == true)
                                    color = currentWord.ErrorColor;
                                else
                                    color = currentWord.WarningColor;

                                for (int lineX = 0; lineX < textWidth + 3; lineX += 4)
                                {
                                    backBuffer.DrawLine(color, new Point(lineX + lineX, lineY), new Point(lineX + lineX + 2, lineY - 2));
                                    backBuffer.DrawLine(color, new Point(lineX + lineX + 2, lineY - 2), new Point(lineX + lineX + 4, lineY));
                                }
                            }
                        }
                        else if (currentWord.Type == WordType.Space && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.DrawTabbedString("·", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;
                        }
                        else if (currentWord.Type == WordType.Tab && showWhitespace == true)
                        {
                            backBuffer.Font = renderItems.FontNormal;
                            backBuffer.DrawTabbedString("»", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                            textWidth = backBuffer.DrawTabbedString(currentWord.Text, x, 0, tabOrigin, textEditorControl.PixelTabSize).Width;

                        }

                        if (currentWord.Pattern != null)
                        {
                            if (currentWord.Pattern.IsSeparator == true)
                            {
                                backBuffer.FillRect(textEditorControl.SeparatorColor, textEditorControl.ViewPoint.TextMargin - 4, 
									textEditorControl.ViewPoint.RowHeight - 1, textEditorControl.ViewPoint.ClientAreaWidth, 1);
                            }
                        }

                        x += textWidth;
                    }

                    if (startDraw == false)
                        row.ExpansionStartChar += currentWord.Text.Length;

                    if (currentWord == startWord)
                        startDraw = true;

                    row.ExpansionEndChar += currentWord.Text.Length;
                }

                if (textEditorControl.TextEditor.ShowEOLMarker == true && expansion == false)
                {
                    backBuffer.Font = renderItems.FontNormal;
                    backBuffer.FontTransparent = true;
                    backBuffer.DrawTabbedString("¶", x, 0, tabOrigin, textEditorControl.PixelTabSize);
                }
            }
        }

		/// <summary>
		/// Renders the caret at the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
		/// <param name="y">Y coordinate position to render the caret at.</param>
        protected virtual void RenderCaret(int rowIndex, int y)
        {
            int startRow = -1;
            int caretPositionY = textEditorControl.Caret.Position.Y;

			Row row = textEditorControl.Document[caretPositionY];
            if (caretPositionY >= 0 && caretPositionY <= textEditorControl.Document.Count - 1)
            {
				if (row.ExpansionEndSegment != null)
                {
					if (row.ExpansionEndSegment.Expanded == false)
                    {
						row = row.ExpansionEndSegment.StartRow;
                        startRow = row.Index;
                    }
                }
            }
			
			bool collapsed = rowIndex == startRow;
            if (rowIndex != caretPositionY && rowIndex != startRow)
                return;

            if (textEditorControl.ViewPoint.Action == TextAction.DragText)
            {
                int position = this.MeasureRow(row, textEditorControl.Caret.Position.X).Width + 1;

                if (collapsed == true)
                {
                    position += row.ExpansionPixelStart;
                    position -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }

                renderItems.BackBuffer.InvertRect(position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart - 1, 0, 
					3, textEditorControl.ViewPoint.RowHeight);

                renderItems.BackBuffer.InvertRect(position + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart, 1, 1, 
					textEditorControl.ViewPoint.RowHeight - 2);
            }
            else
            {
                if (textEditorControl.OverWrite == false)
                {
                    int position = textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;
                    position += this.MeasureRow(row, textEditorControl.Caret.Position.X, row.ExpansionPixelStart).Width + 1;

                    if (collapsed == true)
                    {
                        position += row.ExpansionPixelStart;
                        position -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                    }

                    int textWidth = textEditorControl.ViewPoint.CharWidth / 12 + 1;
                    if (textWidth < 1)
                        textWidth = 1;

                    if (textEditorControl.Caret.Blink == true)
                        renderItems.BackBuffer.InvertRect(position, 0, textWidth, textEditorControl.ViewPoint.RowHeight);

                    if (textEditorControl.IMEWindow == null)
                    {
                        textEditorControl.IMEWindow = new IMEWindow(textEditorControl.Handle, textEditorControl.FontName, textEditorControl.FontSize);
                        this.InitIMEWindow();
                    }

                    textEditorControl.IMEWindow.Location = new Point(position, y);
                }
                else
                {
                    int firstPosition = this.MeasureRow(row, textEditorControl.Caret.Position.X).Width;
                    int nextPosition  = this.MeasureRow(row, textEditorControl.Caret.Position.X + 1).Width;
                    int textWidth = nextPosition - firstPosition;

                    if (collapsed == true)
                    {
                        firstPosition += row.ExpansionPixelStart;
                        firstPosition -= MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                    }

                    int position = firstPosition + textEditorControl.ViewPoint.TextMargin - textEditorControl.ViewPoint.ClientAreaStart;

                    if (textEditorControl.Caret.Blink == true)
                        renderItems.BackBuffer.InvertRect(position, 0, textWidth, textEditorControl.ViewPoint.RowHeight);

                    textEditorControl.IMEWindow.Location = new Point(position, y);
                }
            }
        }

		/// <summary>
		/// Renders the margins' 'properties' (eg. line number, whether the row is bookmarked, etc.) at the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderMargins(int rowIndex)
        {
            GDISurface backBuffer = renderItems.BackBuffer;
            if (textEditorControl.ShowGutterMargin == true)
            {
                backBuffer.FillRect(renderItems.GutterMarginBrush, 0, 0, textEditorControl.ViewPoint.GutterMarginWidth, textEditorControl.ViewPoint.RowHeight);

                if (rowIndex <= textEditorControl.Document.Count - 1)
                {
                    Row row = textEditorControl.Document[rowIndex];
					if (this.RenderDefaultMargins != null)
						this.RenderDefaultMargins(textEditorControl, new RenderMarginEventArgs(row));

                    if (textEditorControl.ViewPoint.RowHeight >= textEditorControl.TextEditor.GutterIcons.ImageSize.Height)
                    {
                        if (row.Bookmarked == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, 1);

                        if (row.Breakpoint == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, 0);
                    }
                    else
                    {
                        int rowHeight = textEditorControl.ViewPoint.RowHeight;

                        if (row.Bookmarked == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, 1);

                        if (row.Breakpoint == true)
                            textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, 0);
                    }

                    if (row.Images != null)
                    {
                        foreach (int imageIndex in row.Images)
                        {
                            if (textEditorControl.ViewPoint.RowHeight >= textEditorControl.TextEditor.GutterIcons.ImageSize.Height)
                                textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, imageIndex);
                            else
                            {
                                int rowHeight = textEditorControl.ViewPoint.RowHeight;
                                textEditorControl.TextEditor.GutterIcons.Draw(Graphics.FromHdc(backBuffer.HDC), 0, 0, rowHeight, rowHeight, imageIndex);
                            }
                        }
                    }
                }
            }

            if (textEditorControl.ShowLineNumbers == true)
            {
                using (Graphics graphics = Graphics.FromHdc(backBuffer.HDC))
                {
					graphics.FillRectangle(Brushes.White, new Rectangle(textEditorControl.ViewPoint.GutterMarginWidth, 0,
						textEditorControl.ViewPoint.LineNumberMarginWidth + 1, textEditorControl.ViewPoint.RowHeight));
                }

				if (textEditorControl.UseDottedMarginBorder == true)
				{
					for (int borderDotIndex = 0; borderDotIndex < textEditorControl.ViewPoint.RowHeight; borderDotIndex += 2)
					{
						backBuffer.FillRect(renderItems.LineNumberMarginBorderBrush, textEditorControl.ViewPoint.GutterMarginWidth +
							textEditorControl.ViewPoint.LineNumberMarginWidth, borderDotIndex, 1, 1);
					}
				}
            }

			if (textEditorControl.ShowLineNumbers == false || textEditorControl.ShowGutterMargin == false)
			{
				backBuffer.FillRect(renderItems.BackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth, 0, textEditorControl.ViewPoint.TextMargin -
					textEditorControl.ViewPoint.TotalMarginWidth - 3, textEditorControl.ViewPoint.RowHeight);
			}
			else
			{
				backBuffer.FillRect(renderItems.BackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth + 1, 0, textEditorControl.ViewPoint.TextMargin - 
					textEditorControl.ViewPoint.TotalMarginWidth - 4, textEditorControl.ViewPoint.RowHeight);
			}

            if (textEditorControl.ShowLineNumbers == true)
            {
                backBuffer.Font = renderItems.FontNormal;
                backBuffer.FontTransparent = true;

                backBuffer.TextForeColor = textEditorControl.LineNumberForeColor;
                if (rowIndex <= textEditorControl.Document.Count - 1)
                {
					string rowText      = (rowIndex + 1).ToString(CultureInfo.InvariantCulture);
                    int    rowTextWidth = this.MeasureString(rowText).Width;

                    backBuffer.DrawTabbedString(rowText, textEditorControl.ViewPoint.GutterMarginWidth + textEditorControl.ViewPoint.LineNumberMarginWidth - 
						rowTextWidth - 1, 1, 0, textEditorControl.PixelTabSize);
                }
            }
        }

		/// <summary>
		/// Renders the expansion of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderExpansion(int rowIndex)
        {
            if (rowIndex <= textEditorControl.Document.Count - 1)
            {
                int startingY = 4;
                Row row = textEditorControl.Document[rowIndex];
                GDISurface backBuffer = renderItems.BackBuffer;

				if (row.Hovered == true)
				{
					backBuffer.FillRect(renderItems.ExpansionBackgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth, 0,
						14, textEditorControl.ViewPoint.RowHeight);

					backBuffer.FillRect(textEditorControl.RowHoverBackColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0,
						3, textEditorControl.ViewPoint.RowHeight);
				}

				if (row.EndSegment != null)
				{
					if (row.ExpansionStartSegment != null && row.StartSegment.Parent == null)
					{
						if (row.IsCollapsed == false)
						{
							backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6, startingY, 1,
								textEditorControl.ViewPoint.RowHeight - startingY);
						}
					}
					else if (row.EndSegment.Parent != null || row.ExpansionEndSegment != null)
					{
						backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6,
							0, 1, textEditorControl.ViewPoint.RowHeight);
					}

					if (row.ExpansionStartSegment != null)
					{
						GDIBrush backgroundBrush = textEditorControl.Document[rowIndex].Expanded == true ? renderItems.BackgroundBrush : renderItems.CollapsedBackgroundBrush;
						GDIBrush symbolBrush = renderItems.SymbolBrush;

						backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 2, startingY, 9, 9);
						backBuffer.FillRect(backgroundBrush, textEditorControl.ViewPoint.TotalMarginWidth + 3, startingY + 1, 7, 7);
						backBuffer.FillRect(symbolBrush, textEditorControl.ViewPoint.TotalMarginWidth + 4, startingY + 4, 5, 1);

						if (row.ExpansionStartSegment.Expanded == false)
							backBuffer.FillRect(symbolBrush, textEditorControl.ViewPoint.TotalMarginWidth + 6, startingY + 2, 1, 5);
					}

					if (row.ExpansionEndSegment != null)
					{
						backBuffer.FillRect(renderItems.OutlineBrush, textEditorControl.ViewPoint.TotalMarginWidth + 7,
							textEditorControl.ViewPoint.RowHeight - 1, 5, 1);
					}
				}

                if (spanFound == true && textEditorControl.TextEditor.ScopeIndicatorColor != Color.Transparent && 
					textEditorControl.TextEditor.ShowScopeIndicator == true)
                {
					if (rowIndex >= firstSpanRow && rowIndex <= lastSpanRow)
					{
						backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0, 2,
							textEditorControl.ViewPoint.RowHeight);
					}

                    if (rowIndex == firstSpanRow)
                        backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14, 0, 4, 2);

					if (rowIndex == lastSpanRow)
					{
						backBuffer.FillRect(textEditorControl.TextEditor.ScopeIndicatorColor, textEditorControl.ViewPoint.TotalMarginWidth + 14,
							textEditorControl.ViewPoint.RowHeight - 2, 4, 2);
					}
                }
            }
        }

		/// <summary>
		/// Renders the selection of the row at the given index.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderSelection(int rowIndex)
        {
			Color borderColor = textEditorControl.ContainsFocus == true ? textEditorControl.SelectionBorderColor : textEditorControl.InactiveSelectionBorderColor;

			GDISurface backBuffer = renderItems.BackBuffer;
			int borderWidth = textEditorControl.SelectionBorderColor == Color.Transparent ? 0 : 1;
            if (rowIndex <= textEditorControl.Document.Count - 1 && textEditorControl.Selection.IsValid)
            {
                Row row = textEditorControl.Document[rowIndex];
                if (row.IsCollapsed == false)
                {
                    if (rowIndex > textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex < textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int actualWidth = this.MeasureRow(row, row.Text.Length).Width + this.MeasureString("¶").Width + 3;
						backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth -
							textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight - borderWidth);

						this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + borderWidth, borderWidth, Math.Max(actualWidth -
							textEditorControl.ViewPoint.ClientAreaStart - borderWidth, 0), textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int startWidth  = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                        int actualWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width - startWidth;
						backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin + startWidth - 
							textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight - 1);

						this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart +
							borderWidth, borderWidth, actualWidth - borderWidth, textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
                    {
                        int actualWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width;
						backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth - 
							textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight - 1);

						this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + borderWidth, borderWidth, Math.Max(actualWidth -
							textEditorControl.ViewPoint.ClientAreaStart - borderWidth, 0), textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                    else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow)
                    {
                        int startWidth = this.MeasureRow(row, Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                        int actualWidth = this.MeasureRow(row, row.Text.Length).Width + this.MeasureString("¶").Width + 3 - startWidth;
						backBuffer.DrawRect(borderColor, textEditorControl.ViewPoint.TextMargin + startWidth - 
							textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight - borderWidth);

                        this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart +
							borderWidth, borderWidth, actualWidth - borderWidth, textEditorControl.ViewPoint.RowHeight - (borderWidth * 2));
                    }
                }
                else
				{
                    this.RenderCollapsedSelection(rowIndex);
                }
            }
        }

		/// <summary>
		/// Renders the selection of the row at the given index as if it were collapsed.
		/// </summary>
		/// <param name="rowIndex">Index of the row.</param>
        protected virtual void RenderCollapsedSelection(int rowIndex)
        {
			GDISurface backBuffer = renderItems.BackBuffer;
            Row row = textEditorControl.Document[rowIndex];
            if (rowIndex > textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex < textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int actualWidth = this.MeasureRow(row, row.ExpansionEndChar).Width;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + 1, 1, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart - 1, 0),
					textEditorControl.ViewPoint.RowHeight - 1);

				backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart, 0),
					textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow && rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int startWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                int minimumLength = Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn);
				minimumLength = Math.Min(minimumLength, row.ExpansionEndChar);

                int actualWidth = this.MeasureRow(row, minimumLength).Width - startWidth;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, actualWidth - 1,
					textEditorControl.ViewPoint.RowHeight - 1);

				backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin + startWidth - 
					textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.LastRow)
            {
                int actualWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.LastColumn)).Width;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + 1, 1, Math.Max(actualWidth - textEditorControl.ViewPoint.ClientAreaStart - 1, 0),
					textEditorControl.ViewPoint.RowHeight - 1);

				backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin, 0, Math.Max(actualWidth - 
					textEditorControl.ViewPoint.ClientAreaStart, 0), textEditorControl.ViewPoint.RowHeight);
            }
            else if (rowIndex == textEditorControl.Selection.LogicalBounds.FirstRow)
            {
                int startWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, textEditorControl.Selection.LogicalBounds.FirstColumn)).Width;
                int actualWidth = this.MeasureRow(row, (int)Math.Min(row.Text.Length, row.ExpansionEndChar)).Width - startWidth;
                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startWidth - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, actualWidth - 1,
					textEditorControl.ViewPoint.RowHeight - 1);

				backBuffer.DrawRect(textEditorControl.OutlineColor, textEditorControl.ViewPoint.TextMargin + startWidth - 
					textEditorControl.ViewPoint.ClientAreaStart, 0, actualWidth, textEditorControl.ViewPoint.RowHeight);
            }

            if (textEditorControl.Selection.LogicalBounds.LastRow > rowIndex && textEditorControl.Selection.LogicalBounds.FirstRow <= rowIndex)
            {
                int startPixel = row.ExpansionPixelEnd;
                int endPixel   = row.ExpansionEndRow.ExpansionPixelStart - startPixel + textEditorControl.ViewPoint.TextMargin;

                this.RenderRectangle(startPixel - textEditorControl.ViewPoint.ClientAreaStart + 1, 1, endPixel - 1, textEditorControl.ViewPoint.RowHeight - 2);
				backBuffer.DrawRect(textEditorControl.OutlineColor, startPixel - textEditorControl.ViewPoint.ClientAreaStart, 0, endPixel, 
					textEditorControl.ViewPoint.RowHeight);
            }

            rowIndex = row.ExpansionEndRow.Index;
            row      = row.ExpansionEndRow;

            if (textEditorControl.Selection.LogicalBounds.FirstRow <= rowIndex && textEditorControl.Selection.LogicalBounds.LastRow >= rowIndex)
            {
                int endCharIndex = 0;

                if (textEditorControl.Selection.LogicalBounds.LastRow == rowIndex)
                    endCharIndex = Math.Min(textEditorControl.Selection.LogicalBounds.LastColumn, row.Text.Length);
                else
                    endCharIndex = row.Text.Length;

				int startPixel = 0;
                int endPixel   = this.MeasureRow(row, endCharIndex, row.ExpansionPixelStart).Width;

                endPixel += row.ExpansionPixelStart;
                endPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;

                if (textEditorControl.Selection.LogicalBounds.FirstRow == rowIndex)
                {
                    int startchar = Math.Max(textEditorControl.Selection.LogicalBounds.FirstColumn, row.ExpansionStartChar);
                    startPixel = this.MeasureRow(row, startchar, row.ExpansionPixelStart).Width;

                    startPixel += row.ExpansionPixelStart;
                    startPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }
                else
                {
                    startPixel = this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;

                    startPixel += row.ExpansionPixelStart;
                    startPixel -= this.MeasureRow(row, row.ExpansionStartChar, row.ExpansionPixelStart).Width;
                }

                endPixel -= startPixel;
                if (textEditorControl.Selection.LogicalBounds.LastRow != rowIndex)
                    endPixel += 6;

                this.RenderRectangle(textEditorControl.ViewPoint.TextMargin + startPixel - textEditorControl.ViewPoint.ClientAreaStart, 0, endPixel,
					textEditorControl.ViewPoint.RowHeight);
            }
        }

        #endregion

        #endregion

        /// <summary>
        /// Initializes a new instance of DefaultPainter.
        /// </summary>
		/// <param name="control">TextEditorBase that the DefaultPainter should be drawing.</param>
        public DefaultPainter(TextEditorBase control)
        {
            textEditorControl = control;
            this.InitGraphics();
        }
    }
}
